package org.ftc.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ftc.form.BasicFilterForm;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.springframework.beans.factory.annotation.Autowired;

public abstract class CurrentDao <T ,ID extends Serializable>  {
	
	@SuppressWarnings("unchecked")
	private Log log = LogFactory.getLog((Class<T>)((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]); 
	 
	@Autowired
	private SessionFactory sessionFactory;
	public Session getSession() { 
	    return sessionFactory.getCurrentSession();
	} 
	
	public Dialect getDialect() { 
	    return ((SessionFactoryImplementor) sessionFactory).getDialect();
	} 
	
	private Class<T> persistentClass;
	
	@SuppressWarnings("unchecked")
	public CurrentDao() {
    	this.persistentClass = (Class<T>)((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }
	
	private Class<T> getPersistentClass() {
        return persistentClass;
    }
	
	public Log getLog(){
		return this.log;
	}
	
	@SuppressWarnings("unchecked")
	public T load(ID id) {
		try{
			return (T)getSession().load(getPersistentClass(), id);
		}catch (Exception e){
			log.error(e.toString());
			return null;
		}
	}
	
	@SuppressWarnings("unchecked")
	public T get(ID id) {
		try{
			return (T)getSession().get( getPersistentClass(), id);
		}catch (Exception e){
			e.printStackTrace();
			log.error(e.toString());
			return null;
		}
	}

	public synchronized boolean save(T entity) {
		try{	
			getSession().save(entity);
			return true;
		}catch( Exception e ){
			e.printStackTrace();
			log.error(e.toString());
			return false;
		}
	}

	public synchronized boolean saveOrUpdate(T entity) {
		try{	
			getSession().saveOrUpdate(entity);
			return true;
		}catch( Exception e ){
			log.error(e.toString());
			return false;
		}
	}

	public synchronized boolean update(T entity) {
		try{	
			getSession().update(entity);
			return true;
		}catch( Exception e ){
			e.printStackTrace();
			log.error(e.toString());
			return false;
		}
	}

	public synchronized boolean delete(T entity) {
		try{	
			getSession().delete(entity);
			return true;
		}catch( Exception e ){
			log.error(e.toString());
			return false;
		}
	}
	
	public synchronized boolean delete(ID id) {
		try{	
			getSession().delete(get(id));
			return true;
		}catch( Exception e ){
			log.error(e.toString());
			return false;
		}
	}
	
	@SuppressWarnings("unchecked")
	public List<T> findPage(int offset, int pageSize) {
		try{	
			Criteria criteria = getSession().createCriteria(getPersistentClass());
			criteria.addOrder(Order.desc("id"));
			criteria.setFirstResult(offset);
			criteria.setMaxResults(pageSize);
			List<T> list = (List<T>) criteria.list();
			return list; 
		}catch( Exception e ){
			log.error(e.toString());
			return null;
		}
	}
	
	@SuppressWarnings("unchecked")
	public List<T> findAll() {
		try{	
			Criteria criteria = getSession().createCriteria(getPersistentClass());
			criteria.addOrder(Order.asc("id"));
			criteria.setCacheable(true);
			List<T> list = (List<T>) criteria.list();
			return list; 
		}catch( Exception e ){
			log.error(e.toString());
			return null;
		}
	}

	public long countAll() {
		try{	
			Criteria criteria = getSession().createCriteria(getPersistentClass()); 
		    criteria.setProjection(Projections.rowCount()); 
		    criteria.setCacheable(true);
		    return (Long) criteria.uniqueResult();
		}catch( Exception e ){
			log.error(e.toString());
			return 0; 
		}
	}
	
	public void criteriaSort(BasicFilterForm form, Criteria criteria){
		if( form.getSort() != null && form.getSort().length > 0 ){
			for(int i = 0; i < form.getSort().length; i++){
				if( "desc".equals(form.getOrder()[i] ) ){
					criteria.addOrder(Order.desc(form.getSort()[i]));
				}else{
					criteria.addOrder(Order.asc(form.getSort()[i]));
				}
			}
		}
	}
	
	public void criteriaSort(String sort ,String order, Criteria criteria){
		if( sort != null && sort.length() > 0 ){
			if( "desc".equals(order) ){
				criteria.addOrder(Order.desc(sort));
			}else{
				criteria.addOrder(Order.asc(sort));
			}
		}
	}
	
	public List<T> getList(final Criteria criteria){
		@SuppressWarnings("unchecked")
		List<T> list = (List<T>)criteria.list();
		return list;
	}
}
